import { EventToPlayerCacheService } from './../event-to-player/event-to-player.cache.service';
import { Injectable } from '@nestjs/common';
import { CreateGameDto } from './dto/create-game.dto';
import { GameInfoV2 } from './entities/game.entity.v2';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import logger from 'src/common/utils/log';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { MatchCacheService } from 'src/modules/match/match.cache.service';

@Injectable()
export class GameService {
  constructor(
    @InjectRepository(GameInfoV2)
    private readonly repository: Repository<GameInfoV2>,
    private eventEmitter: EventEmitter2,
    private matchCacheService: MatchCacheService,
  ) {}
  async saveList(games: GameInfoV2[]) {
    return this.repository.save(games);
  }
  async create(createGameDto: CreateGameDto) {
    logger.info(
      `createGameDto start ${createGameDto.homePlayerId} / ${createGameDto.awayPlayerId} / ${createGameDto.matchInfo?.id}/ ${createGameDto.progress?.length}`,
    );
    // 直接给大屏发送数据，不过数据库了
    // this.eventEmitter.emit('game.rallyUpdate', createGameDto);
    await this.updateScoreScreen(createGameDto);
    const newEntity = this.saveAndUpdateByMatchIdAndGameIndex(createGameDto);
    logger.debug('gameService.create newEntity:', newEntity);
    return newEntity;
  }
  async updateScoreScreen(createGameDto: CreateGameDto) {
    const scoreScreenData = await this.getScoreScreenData(createGameDto);
    this.eventEmitter.emit('game.rallyUpdate', scoreScreenData);
  }

  async getScoreScreenData(createGameDto: CreateGameDto) {
    const { matchInfo } = createGameDto;
    const { subMatchId } = matchInfo;
    let parentMatch = null;
    if (subMatchId) {
      // 更新付比赛数据
      parentMatch = await this.matchCacheService.getMatch(subMatchId);
    }
    return {
      ...createGameDto,
      parentMatch,
    };
  }

  async saveAndUpdateByMatchIdAndGameIndex(
    createGameDto: CreateGameDto,
  ): Promise<GameInfoV2> {
    try {
      if (createGameDto.id) {
        const entity = this.repository.create(createGameDto);
        await this.repository.save(entity);
        return entity;
      } else {
        const entity = await this.repository
          .createQueryBuilder('gameInfo')
          .where('gameInfo.matchId = :matchId', {
            matchId: createGameDto.matchId || createGameDto.matchInfo.id,
          })
          .andWhere('gameInfo.gameIndex = :gameIndex', {
            gameIndex: createGameDto.gameIndex,
          })
          .getOne();
        const newEntity = this.repository.create(createGameDto);
        if (entity) {
          newEntity.id = entity.id;
        }
        const res = await this.repository.save(newEntity);
        return res;
      }
    } catch (e) {
      logger.error('saveAndUpdateByMatchIdAndGameIndex error', e);
      throw e;
    }
  }

  findOne(id: number) {
    return this.repository.findOne({ where: { id } });
  }

  async getMatchDetail(id: number) {
    const gameInfo = await this.repository
      .createQueryBuilder('gameInfo')
      .leftJoinAndSelect('gameInfo.matchInfo', 'matchInfo')
      .leftJoinAndSelect('matchInfo.group', 'group')
      .leftJoinAndSelect('matchInfo.playground', 'playground')
      .leftJoinAndSelect('group.stage', 'stage')
      .leftJoinAndSelect('stage.event', 'event')
      .leftJoinAndSelect('event.category', 'category')
      .leftJoinAndSelect('event.eventToPlayers', 'eventToPlayers')
      // .leftJoinAndSelect('eventToPlayers.player', 'player')
      .leftJoinAndSelect('category.tournament', 'tournament')
      .where('gameInfo.id = :id', { id })
      .getOne();
    const { matchInfo, ...gameRest } = gameInfo;
    const { group, playground, ...matchRest } = matchInfo;
    const { stage, ...groupRest } = group;
    const { event, ...stageRest } = stage;
    const { category, ...eventRest } = event;
    const { tournament, ...categoryRest } = category;
    const res = {
      gameInfo: gameRest,
      matchInfo: matchRest,
      group: groupRest,
      playground,
      stage: stageRest,
      event: eventRest,
      category: categoryRest,
      tournament,
    };
    return res;
  }

  async findInMatchIds(matchIds: number[]) {
    const gameInfos = await this.repository
      .createQueryBuilder('gameInfo')
      .where('gameInfo.matchId IN (:...matchIds)', { matchIds })
      .getMany();
    return gameInfos;
  }
  async findByMatchId(matchId: number) {
    const gameInfos = await this.repository
      .createQueryBuilder('gameInfo')
      .where('gameInfo.matchId = :matchId', { matchId })
      .getMany();
    return gameInfos;
  }

  async removeIds(ids: number[]) {
    return this.repository.delete(ids);
  }
}
